package ru.spb.osll.myfit.server;

import org.apache.log4j.Logger;
import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.PageTag;
import ru.spb.osll.myfit.common.Suite;
import ru.spb.osll.myfit.common.TextParsingTools;
import ru.spb.osll.myfit.common.util.Pair;
import ru.spb.osll.myfit.server.fixtureiterator.FileFactory;
import ru.spb.osll.myfit.server.handler.ContentCreator;
import ru.spb.osll.myfit.server.handler.ContentHandler;
import ru.spb.osll.myfit.server.handler.PageLoader;
import ru.spb.osll.myfit.server.handler.ParentVariablesCreator;
import ru.spb.osll.myfit.server.parser.PageUtils;
import ru.spb.osll.myfit.server.parser.SuiteHandler;
import ru.spb.osll.myfit.server.parser.TableUtils;
import ru.spb.osll.myfit.server.templateloader.JarTableTemplateLoader;
import ru.spb.osll.myfit.util.CollectionUtils;
import ru.spb.osll.myfit.util.Filter;

import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static ru.spb.osll.myfit.server.parser.PageUtils.getFullPath;


/**
 * Common logic for {@link ru.spb.osll.myfit.server.services.SuiteServiceImpl} and and {@link ru.spb.osll.myfit.server.execute.SuiteExecutingServiceImpl}
 */
public class SuiteUtils {
  private static final ContentHandler s_contentHandler;
  private static final String s_root;
  private static Configurator m_configurator;
  private static Logger m_logger = Logger.getLogger(SuiteUtils.class);

  static {
    m_configurator = Configurator.getInstance();
    s_root = m_configurator.getRootDir();

    URLClassLoader classLoader = new MyFitClassLoaderFactory(
            new FileFactory()).createClassLoader(m_configurator.getDependenciesDir(),
            m_configurator.getFixtureDir());
    JarTableTemplateLoader templateLoader = new JarTableTemplateLoader(
            m_configurator.getFixtureDir(), classLoader);
    Map<String, Class<?>> fixtureClasses = templateLoader.getFixtureClasses();
    PageLoader pageLoader = new PageLoader(new TableUtils(fixtureClasses));
    s_contentHandler = new ContentHandler(s_root,
            pageLoader, new ContentCreator(), new ParentVariablesCreator(pageLoader));
  }

  public static List<String> getSuitePages(Suite suite) {
    final List<String> pagesPaths = new ArrayList<String>();

    fillPagesPaths(suite.getRoot(), pagesPaths);

    return pagesPaths;
  }

  public static List<String> getSuitePagesFilteredByTags(Suite suite) {
    final Set<PageTag> tags = suite.getTags();

    return CollectionUtils.filter(getSuitePages(suite), new Filter<String>() {
      @Override
      public boolean passes(String arg) {
        Page page = s_contentHandler.loadPage(arg);
        return page != null && page.containsTags(tags);
      }
    });
  }

  private static void fillPagesPaths(String path, List<String> pagesPaths) {
    File testDirectory = new File(PageUtils.getFullPath(s_root, path));
    if (!testDirectory.exists())
      return;

    if (path != null && !path.isEmpty())
      pagesPaths.add(path);

    File[] subTests = testDirectory.listFiles(new FileFilter() {
      public boolean accept(File file) {
        return file.isDirectory();
      }
    });

    if (subTests == null)
      return;

    String pathPrefix = path == null || path.isEmpty() ? "" : path + TextParsingTools.ADDRESS_BAR_SEPARATOR;

    for (File subTest : subTests) {
      fillPagesPaths(pathPrefix + subTest.getName(), pagesPaths);
    }
  }

  public static String getSuitePathFromId(String id) {
    String suitesDirectory = m_configurator.getSuitesDir();

    String suiteDirectoryPath = getFullPath(suitesDirectory, id);

    String suiteFilePath = suiteDirectoryPath + File.separator + TextParsingTools.getPostfix(id, TextParsingTools.ADDRESS_BAR_SEPARATOR) + ".xml";

    return suiteFilePath;
  }

  public static List<Pair<String, Boolean>> getSuites(String path) {
    final List<Pair<String, Boolean>> suites = new ArrayList<Pair<String, Boolean>>();

    String suitesRootDir = Configurator.getInstance().getSuitesDir();
    File suiteDir = new File(PageUtils.getFullPath(suitesRootDir, path));
    if (!suiteDir.exists() || !suiteDir.isDirectory())
      return suites;

    File[] subSuites = suiteDir.listFiles();

    if (subSuites == null)
      return suites;

    final SuiteHandler suiteHandler = new SuiteHandler();

    for (File suiteFile : subSuites) {
      String pathPrefix = path == null || path.isEmpty() ? "" : path + TextParsingTools.ADDRESS_BAR_SEPARATOR;
      try {
        suiteHandler.getSuite(getSuitePathFromId(pathPrefix + suiteFile.getName()));
      } catch (FileNotFoundException e) {
        m_logger.error(e.getMessage() + "\n" + e.getStackTrace());
        continue;
      } catch (ParserConfigurationException e) {
        m_logger.error(e.getMessage() + "\n" + e.getStackTrace());
        continue;
      }

      File[] children = suiteFile.listFiles(new FileFilter() {
        @Override
        public boolean accept(File file) {
          return file.isDirectory();
        }
      });

      Boolean hasChild = children != null && children.length != 0;

      suites.add(new Pair<String, Boolean>(suiteFile.getName(), hasChild));
    }

    return suites;
  }
}
